/**
 * This software was produced for the U. S. Government
 * under Contract No. FA8721-09-C-0002, and is
 * subject to the Rights in Noncommercial Computer Software
 * and Noncommercial Computer Software Documentation Clause
 * (DFARS) 252.227-7014 (JUN 1995)
 * 
 * (c) 2009 The MITRE Corporation. All Rights Reserved.
 *
 * SPMIF to OPNET Translator
 * Author: ewalters
 * Created: 11:15:28 AM, Aug 9, 2007
 * MITRE Corporation
 */
package com.mitre.spmif2opnet.analysis.ast;

import java.util.Properties;

import com.mitre.spmif2opnet.spmif.DeviceFeatureType;
import com.mitre.spmif2opnet.spmif.SchedulingPolicyType;

/**
 * Represents an abstract device (in concept, not class) gleaned from S-PMIF info
 */
public class Device {
	/**
	 *  What category of functionality does this device belong to?
	 * @author EWALTERS
	 */
	public enum DeviceCategory {
		DEVICE_PROCESSING,   // Does computation
		DEVICE_NETWORK,      // Effects of network travel
		DEVICE_PACKET_SIZE,  // Network Packet Sizes
		DEVICE_STORAGE,      // Storage (Disk) element
		DEVICE_PASSIVE,      // Switch/Router
		DEVICE_OTHER;        // Other items we can't figure out or don't care about
	}
	
	/**
	 * Name of the device
	 */
	private String _name;
	/**
	 * Id of the device
	 */
	private String _id;
	/** 
	 * Device category
	 */
	private DeviceCategory _cat;
	/**
	 * How many of this device is available?
	 */
	private int _quantity;
	/**
	 * What is the S-PMIF feature type of this device?
	 */
	private DeviceFeatureType _feature;
	/**
	 * What is the S-PMIF scheduling policy type of this device?
	 */
	private SchedulingPolicyType _policy;
	/**
	 * What are the service units of this device?
	 */
	private ServiceUnitType _service_units;
	/**
	 * How much time does the device need?
	 */
	private double _service_time;
	/**
	 * What is the model name (i.e. hardware description) of the device?
	 * Used for OPNET identification
	 */
	private String _model_name;
	/**
	 * What is the extended description of the device?
	 * Used for OPNET identification
	 */
	private String _long_model_name;
	/**
	 * What is the OPNET jov class?
	 */
	private String _job_class;
	/** 
	 * Java properties - fills in many of the names
	 */
	private Properties _props;
	
	/**
	 * Default constructor
	 * @param name device name
	 * @param id device id
	 * @param quantity device quantity
	 * @param feature device features
	 * @param policy device scheduling policy
	 * @param serv_units device service units
	 * @param serv_time device service time
	 * @param props Java props
	 */
	public Device(String name, String id, int quantity, DeviceFeatureType feature,
			SchedulingPolicyType policy, String serv_units, double serv_time, Properties props) {
		_name = name;
		_id = id;
		_quantity = quantity;
		_feature = feature;
		_policy = policy;
		_service_units = ServiceUnitType.fromString(serv_units);
		_service_time = serv_time;
		_props = props;
		this.inferCategory();
		this.inferModel();
	}
	
	/**
	 * This method contains general heuristics to infer the category, i.e.
	 * how we will translate this device into an OPNET equivalent, from 
	 * the information contained within the device.
	 */
	private void inferCategory() {
		String s = _name.toLowerCase();
		if (s.contains("process") || s.contains("cpu") || s.contains("machine")) {
			_cat = DeviceCategory.DEVICE_PROCESSING;
		} else if (s.contains("passive")) {
			_cat = DeviceCategory.DEVICE_PASSIVE;
		} else if (s.contains("network")) {
			_cat = DeviceCategory.DEVICE_NETWORK;
		} else if (s.contains("storage") || s.contains("disk")) {
			_cat = DeviceCategory.DEVICE_STORAGE;
		} else {
			_cat = DeviceCategory.DEVICE_OTHER;
		}
	}
	
	/**
	 * Using the device info, pick out what kind of device we want to use in what circumstances
	 * Please excuse the magic names
	 */
	private void inferModel() {
		String def_model = "Sun_Ultra_10_333";
		String def_long_model = "Sun Ultra 10 333MHz:: 1 CPU, 1 Core(s) Per CPU, 333MHz, Solaris, System";
		String def_job_class = "SPECint_2000";
		if (_quantity == 2) { 
			_model_name = _props.getProperty("TwoCoreModel");			
			_long_model_name = _props.getProperty("TwoCoreModelLongName");
			_job_class = _props.getProperty("TwoCoreJobClass");
		} else if (_cat.equals(Device.DeviceCategory.DEVICE_PASSIVE)) {
			_model_name = _props.getProperty("PassiveModel");
			_long_model_name = _props.getProperty("PassiveModelLongName");
			_job_class = _props.getProperty("PassiveJobClass");  // NOTE: Needed?
		} else {
			_model_name = _props.getProperty("StandardModel");
			_long_model_name = _props.getProperty("StandardModelLongName");
			_job_class = _props.getProperty("StandardJobClass");
		}
		if (_model_name == null) _model_name = def_model;
		if (_long_model_name == null) _long_model_name = def_long_model;
		if (_job_class == null) _job_class = def_job_class;
	}
	
	/**
	 * Name accessor
	 * @return the name
	 */
	public String getName() {
		return _name;
	}
	
	/**
	 * Id accessor
	 * @return the id
	 */
	public String getId() {
		return _id;
	}
	
	/**
	 * Category accessor
	 * @return the category
	 */
	public DeviceCategory getCategory() {
		return _cat;
	}
	
	/**
	 * Is this device a processing device?
	 * @return is it?
	 */
	public boolean isProcessingDevice() {
		return (_cat.equals(DeviceCategory.DEVICE_PROCESSING));
	}
	
	/**
	 * Is this device a network transaction?
	 * @return is it?
	 */
	public boolean isNetworkingDevice() {
		return (_cat.equals(DeviceCategory.DEVICE_NETWORK));
	}
	
	/**
	 * service time accessor
	 * @return the time
	 */
	public double getServiceTime() {
		return _service_time;
	}

	/** 
	 * Does this device conform to the input category?
	 * @param cat the category
	 * @return does it conform?
	 */
	public boolean isCategory(DeviceCategory cat) {
		return _cat.equals(cat);
	}

	/**
	 * service unit accesor
	 * @return the units
	 */
	public ServiceUnitType getServiceUnits() {
		return _service_units;
	}

	/**
	 * quantity accessor
	 * @return the quantity
	 */
	public int getQuantity() {
		return _quantity;
	}
		
	/**
	 * feature accessor
	 * @return the feature
	 */
	public DeviceFeatureType getFeatureType() {
		return _feature;
	}
	
	/**
	 * scheduling policy accessor
	 * @return the policy
	 */
	public SchedulingPolicyType getPolicy() {
		return _policy;
	}
	
	/**
	 * model name accessor
	 * @return the model name
	 */
	public String getModelName() {
		return _model_name;
	}
	
	/**
	 * long model name accessor
	 * @return the model name
	 */
	public String getLongModelName() {
		return _long_model_name;
	}
	
	/**
	 * Job class accessor
	 * @return the class
	 */
	public String getJobClass() {
		return _job_class;
	}
}
